ハイパフォーマンスブラウザネットワーキング まとめ
3章
UDPはヌルプロトコルと呼ばれる。
TCPで飛ばされるデータブロックはパケット
UDPで飛ばされるデータブロックはデータグラム
TCPとUDPの違うところは順序や欠損の保証があるかないか。
UDPを使おうとすると、NAT問題が発生する。
NATは、そもそもipv4のアドレスが枯渇してしまったが故に、一つ一つのデバイスにIPの振り分けが行えなくなったことから作られた。
NATデバイスはローカルネットワークに置いて、個々の機器に、グローバルIP+portをプライベートIPに変換する辞書を持っている。
これによってローカルネットワークの個々のデバイスはグローバルIPを持つ必要がない。
しかし、UDPではこのNAT(Network Address Translator)が問題を起こしてしまう。
問題点は、データを配信するために管理する必要があるルーティングテーブル。NATは接続状態に依存しているが、UDPにはその状態がなく、そこで食い違いが発生する。TCPであれば接続状態を監視して、必要に応じてルーティングエントリの作成や削除ができるが、UDPの場合にはハンドシェイクも接続終了も存在したいため、監視する場所が存在しない。(UDPには接続終了シーケンスが存在しない。なのでいつ終わったかわからない)
== ルーティングエントリの作成や削除ができない?
== UDPのルーティングレコードはタイマーによって失効するようになっている。(ベンダの設定依存)
UDP+NATに置いて、接続状態の監視ができない以上に大きな問題
そもそも接続か確立できない。
なぜかというと、そもそもブラウザ(クライアント)が自身のパブリックIPを把握できず、把握できないためそれを相手に伝えられないため。厳密にいえば、自身の内部IPアドレスはわかるが、NATデバイスがパケットの中身の送信元ポート番号と、IPアドレスの送信元IPアドレスを書き換えて、パブリックIPに変更するため。どのプライベートIPはNATデバイスの辞書の中に格納されている。
また、外部から自身(ローカルのクライアント)にデータを受け取るためには、NATデバイスの中にその情報(ルーティングエントリ=publicIP+portと、privateIPの紐付け)がなければいけない。しかしそのエントリが存在しているかはわからない。(多くの場合はそのエントリは存在しないらしい?)
そのエントリが存在していない状態でデータが送られると、そのパケットは破棄されてしまう。(インバウンドパケットの破棄)
そこで、NATトラバーサル(NAT横断)技術として、STUN/TURN/ICEがある。
NAT トラバーサル
STUN(session Traversal Utilities for NAT): 自身のネットワーク上のNATデバイスを見つけ、自身の現在の接続に割り当てられているpublicIP+Portの組み合わせを取得する。 これを実現するためには、パブリックネットワークに存在するSTUNサーバーの助けを借りる必要がある。
まず、STUNサーバーへ、バインディングリクエストを送信する。この際にNATを経由するので、その段階でルーティングエントリが作成される
次に、STUNサーバーはそのクライアントを外部から見たときのpublicIPとportをレスポンスする
STUNプロトコルは、キープアライブのメカニズムが定義されていて、NATのルーティングエントリの削除タイマーをリセットする(タイムアウトを防止する)(UDPはタイマーでエントリが削除されてしまうため)
STUNで解決できないとき(92%くらいは解決できるby google)
残念なことに、ファイアウォールなどによって、UDPが完全にブロックされてしまうことがある。企業のネットワークではありがち
その場合には、TURN(Traversal Using Relays around NAT)を使用して、TCPで無理やり動かす。
TURNサーバーは、リレーサーバーとして機能し、パケットをただ右から左に受け流す。
NATトラバーサルの構築
NATトラバーサルの構築は大変らしい?そこで、いいものが定義されている。
STUN・TURNを組み合わせて自動でやってくれるものがICEプロトコル。
可能な限り直接接続を行い、必要ならSTUNを使い、それでも無理ならTURNでTCPで接続してくれる
4章 TLS
TLSの役割
SSLはTLSの前身(by netscape)
暗号化: 公開鍵暗号方式を用いている。
認証:
データ整合性の保証: 改ざんや偽造を検出する。メッセージ認証コードMAC(Message Authentication Code)で署名する。
MACアルゴリズム
ハッシュ関数で暗号化する。TLSレコードが送信される場合には、常にMAC値が生成されてメッセージに付与される。これを受信者は確認して信頼する。 TLSでは、TLSレコードプロトコルによって処理されるデータブロックのことをTLSレコードと呼ぶ。
TLSレコード
データ長と暗号化を行ったデータとMACを格納する
RSAハンドシェイクとDiffie-Hellman鍵交換への置き換え・前方秘匿性
RSAハンドシェイクは昔はシェアを占めていた鍵交換メカニズムだった。しかし、常に同じ公開鍵・秘密鍵のペアがサーバーの認証と共通鍵の暗号化に使用されるため、秘密鍵を入手した場合、全てのデータ通信を復号できてしまう。また、暗号化されていても、データを持っておいて、秘密鍵が入手できたときに復号できてしまう
Diffie-Hellman鍵交換を行うとmハンドシェイクで鍵そのものを直接やりとりすることなく共通鍵のネゴシエートができる。
また、短命な共通鍵を生成し、定期的に破棄することによって、過去のデータを復元することができなくなる。これによって秘密鍵を盗まれたとしても前方秘匿性が担保できる
また、公開鍵暗号方式よりも、共通鍵暗号方式の方がコストが少ないため、通信量の削減にもなる
openssl speed ecdh
openssl speed ses
の二つを比べてみると、acdhの方が遅いことがわかる。直接比較できる訳ではないが、とりあえず遅いことはわかる
ALPN(Application Layer Protocol Negotiation)
カスタムアプリケーションプロトコルを使いたいとき、80/443以外のポートを設定するのは結構大変。
FWなどが邪魔したりするし、ウェルノウンポートを設定するには承認が必要となる?
そのため、HTTP/HTTPSはアップグレードメカニズムを提供している。
ALPNは、HTTP・HTTPSのアップグレードメカニズムを利用する際に必要となるネゴシエートを省略できるもの。(ネゴシエートするためのパケット1往復分を省ける)
これは、TLSハンドシェイクの一部としてプロトコルのネゴシエーションができるから?
NPN(Next Protocol Negotiaion)] は、SPDYプロジェクトが動いていた時に決められたTLS拡張のこと。ALPNとは同等のもの。
サポートしているプロトコルをサーバから送信して、クライアントはプロトコルを選択していた。ALPNでは、逆にクライアントからサポートしているプロトコルをクライアントから送信し、サーバーがその中からプロトコルを選択する。こうなった理由は、他のプロトコルネゴシエーション標準に近くなるため。?
NPNは廃止されてALPNに置き換えられた。
SNI(Server Name Indication)
暗号化されたTLSトンネルは任意の二つのTCPピア間で確率できる。
それぞれがTLS証明書をもつ複数の独立したサイトを単一のIPアドレスでホストしたい場合はどうなるか?
=> そうなると、そのTCPピアかどうか判別しないのでわからない
このように、単一のIPアドレスに紐づいている複数のTLSトンネルがある場合に対応するため、SNI拡張がTLSプロトコルに
導入されている。
短縮ハンドシェイク(TLSセッション再開 TLS Session Resumption)
完全なTLSハンドシェイクにより発生するレイテンシはアプリケーションに大きな負荷を与える。
そのため、複数回に渡す接続で、ネゴシエート済みの秘密鍵を再利用・共有する機能を有している。
クライアントとサーバの両者が共有セッションIDパラメータをキャッシュしている場合は短縮ハンドシェイクを行うことができる。
これによってパケット一往復を取り除くことができる。
実際にはほとんどのウェブアプリケーションは並列してリソースを取得するために同一のホストとの間に複数の接続を確立する。そのため、セッション再開は絶対に必要な最適化となっている
信頼チェーンと認証局
TLS/SSL接続には、必ず証明書が必要となる。
公開鍵暗号方式では、以下の段階で行う
お互いに公開鍵と秘密鍵を生成する
秘密鍵を隠して持っておく
公開鍵を相手に渡す
秘密鍵で署名したメッセージを相手に渡す
受け取った公開鍵でそのメッセージを検証する
A->B->Cというメッセージの転送では、Aが送信したメッセージをBが信頼してCに渡す。その場合、CはBの公開鍵を持っていて、Bが署名したことは検証できるため、Bが署名しているのであれば問題ないだろうとAのメッセージも信頼できる。これが信頼チェーン
chromeで証明書を確認した時に、どのような信頼チェーンになっているかを確認できる。一番上がルート認証局で、各ブラウザはroot認証局のリストを持っている。これも信頼チェーンによって、rootが信頼している一個下の認証局を信頼し、さらにその下の認証局を信頼している。
証明書失効リストCRL(Certificate Revocation List)
認証局は失効した証明書のシリアル番号のリストを管理して定期的に公開している。
証明書の検証を行うものは失効リストをダウンロードして確認する。
これによってどの証明書が失効しているかはわかるが、クライアントはシリアル番号のリスト全てを取得しなければならず、面倒である。
そこで、オンライン証明書状態プロトコルOCSP(Online Sertiificate Status Protocol)が定義されている。子によって、問題となっている証明書のシリアル番号だけで証明書データベースに問い合わせることができる。これによってはるかに小さな帯域幅で行える。
実際には、CRLとOCSPは相互に補完する関係で、ほとんどの証明書は両者を使用するための機能を有している。
OCSPも完全ではなく、リアルタイムにクエリを走らせたり、常に利用可能状態である必要があったり、問題があるため。
TLSの最適化の重要性
現代において、TLSのCPU使用率は1%にも満たない。それでいてもなお、TLSセッション再開(TLS Session Resumption)は重要な最適化技術である。TLSハンドシェイクの際に発生する計算コストと、公開鍵暗号のレイテンシを減少させることにはまだ価値があるとされている。重要性は減ったけどまだ重要らしい?
TLSハンドシェイクでは、最大で二往復、短縮ハンドシェイクでは一往復が必要となる。TCPとTLSの接続確立に3往復が必要となる場合もある。
ニューヨーク・ロンドン間では1往復に59msかかった。つまり三往復だとそれだけで177msかかってしまう。300msの遅延で人間が遅いと感じるレベルなので、これは致命的。
なので物理的にサーバーを近くする処置が増える
TLSセッションキャッシュとステートレスセッション再開
何もデータを送らないことほど早いものはない。そもそも送信しないようにすることはとても重要な観点
サーバーにTLSを設定する場合、セッションIDがデフォルトでONになっている訳ではなく、多くの場合OFf担っているので、これは修正するべき
複数プロセスやワーカーを走らせているサーバーは共有のセッションキャッシュを使用すべき
共有セッションキャッシュのサイズはトラフィック量によって調整されるべき
セッションタイムアウトが設定されるべき
複数サーバーの環境において、同一クライアントIPもしくは同一TLSセッションIDを常に同じサーバーにルーティングすることがセッションキャッシュを効率的に使用する方法の一つである。